﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Media.Animation;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Microsoft.Surface.Presentation;
using Microsoft.Surface.Presentation.Controls;
using Microsoft.Surface.Presentation.Input;
using System.Collections.ObjectModel;
using navigation.Data;

namespace navigation.Controls
{
    /// <summary>
    /// Interaction logic for ScrumBoardTasksContainer.xaml
    /// </summary>
    public partial class ScrumBoardTasksContainer : UserControl
    {
        public ScrumBoardTasksContainer()
        {
            InitializeComponent();
        }

        #region DependencyProperty Initialize

        public static DependencyProperty StoryNameProperty = DependencyProperty.Register("StoryName", typeof(string), typeof(ScrumBoardTasksContainer));

        public string StoryName
        {
            get
            {
                return (string)GetValue(ScrumBoardTasksContainer.StoryNameProperty);
            }
            set
            {
                SetValue(ScrumBoardTasksContainer.StoryNameProperty, value);
            }
        }

        public static DependencyProperty ItemsProperty = DependencyProperty.Register("Items", typeof(ObservableCollection<Task>), typeof(ScrumBoardTasksContainer));

        public ObservableCollection<Task> Items
        {
            get
            {
                return (ObservableCollection<Task>)GetValue(ScrumBoardTasksContainer.ItemsProperty);
            }
            set
            {
                SetValue(ScrumBoardTasksContainer.ItemsProperty, value);
            }
        }

        #endregion

        #region Events
        private void OnDragSourcePreviewTouchDown(object sender, TouchEventArgs e)
        { 
            FrameworkElement findSource = e.OriginalSource as FrameworkElement;
            SurfaceListBoxItem draggedElement = null;

            // Find the touched SurfaceListBoxItem object.
            while (draggedElement == null && findSource != null)
            {
                if ((draggedElement = findSource as SurfaceListBoxItem) == null)
                {
                    findSource = VisualTreeHelper.GetParent(findSource) as FrameworkElement;
                }
            }            

            if (draggedElement == null || !(draggedElement.DataContext is Task))
            {
                return;
            }

            // Create the cursor visual.
            ContentControl cursorVisual = new ContentControl()
            {
                Content = draggedElement.DataContext,
                Style = FindResource("CursorStyle") as Style
            };

            // Add a handler. This will enable the application to change the visual cues.
            SurfaceDragDrop.AddTargetChangedHandler(cursorVisual, OnTargetChanged);

            // Create a list of input devices. Add the touches that
            // are currently captured within the dragged element and
            // the current touch (if it isn't already in the list).
            List<InputDevice> devices = new List<InputDevice>();
            devices.Add(e.TouchDevice);
            foreach (TouchDevice touch in draggedElement.TouchesCapturedWithin)
            {
                if (touch != e.TouchDevice)
                {
                    devices.Add(touch);
                }
            }

            // Get the drag source object
            ItemsControl dragSource = ItemsControl.ItemsControlFromItemContainer(draggedElement);

            SurfaceDragCursor startDragOkay =
                SurfaceDragDrop.BeginDragDrop(
                  dragSource,                 // The SurfaceListBox object that the cursor is dragged out from.
                  draggedElement,             // The SurfaceListBoxItem object that is dragged from the drag source.
                  cursorVisual,               // The visual element of the cursor.
                  draggedElement.DataContext, // The data associated with the cursor.
                  devices,                    // The input devices that start dragging the cursor.
                  DragDropEffects.Move);      // The allowed drag-and-drop effects of the operation.

            // If the drag began successfully, set e.Handled to true. 
            // Otherwise SurfaceListBoxItem captures the touch 
            // and causes the drag operation to fail.
            e.Handled = (startDragOkay != null);
            draggedElement.Visibility = System.Windows.Visibility.Hidden;
            Items.Remove(draggedElement.DataContext as Task);
        }

        private void LibraryStackPreviewTouchDown(object sender, TouchEventArgs e)
        {
            FrameworkElement findSource = e.OriginalSource as FrameworkElement;
            LibraryStackItem draggedElement = null;

            // Find the touched SurfaceListBoxItem object.
            while (draggedElement == null && findSource != null)
            {
                if ((draggedElement = findSource as LibraryStackItem) == null)
                {
                    findSource = VisualTreeHelper.GetParent(findSource) as FrameworkElement;
                }
            }

            if (draggedElement == null || !(draggedElement.DataContext is Task))
            {
                return;
            }

            Task item = draggedElement.DataContext as Task;
            item.DraggedElement = Items;
        }

        private void TasksListBox_DragCanceled(object sender, SurfaceDragDropEventArgs e)
        {
            //Console.WriteLine("cancel");
            Task item = e.Cursor.Data as Task;
            Items.Add(item);
        }

        private void TasksListBox_DragCompleted(object sender, SurfaceDragCompletedEventArgs e)
        {
            if (e.Cursor.CurrentTarget is LibraryStack)
            {
                Items.Remove(e.Cursor.Data as Task);
            }
            else if (e.Cursor.CurrentTarget is SurfaceListBox && e.Cursor.CurrentTarget.Name == "TasksListBox")
            {
                // manipulation
                //MessageBox.Show("1");
            }
            else
            {
                Task item = e.Cursor.Data as Task;
                Items.Add(item);
            }
        }

        private void TasksListBox_OnDropTargetDrop(object sender, SurfaceDragDropEventArgs e)
        {
            if (e.Cursor.Data is Task)
            {
                if (Items.Contains(e.Cursor.Data as Task))
                {
                    int index = this.GetListBoxItemCurrentIndex(TasksListBox, e.Cursor.GetPosition);
                    int indexOfDraggedElement = Items.IndexOf(e.Cursor.Data as Task);

                    if (index < 0 || index > TasksListBox.Items.Count - 1)
                    {
                        Task temp = Items[indexOfDraggedElement];
                        Items.RemoveAt(indexOfDraggedElement);
                        Items.Add(temp);
                    }
                    else
                    {

                        Task temp = Items[indexOfDraggedElement];
                        Items.RemoveAt(indexOfDraggedElement);
                        Items.Insert(index, e.Cursor.Data as Task);
                    }
                }
                else
                {
                    int index = this.GetListBoxItemCurrentIndex(TasksListBox, e.Cursor.GetPosition);

                    if (index < 0 || index > TasksListBox.Items.Count - 1)
                        index = TasksListBox.Items.Count;

                    Items.Insert(index, e.Cursor.Data as Task);
                }
            }

        }

        // effect of the task card when drag into the listbox or move out, 
        // the border will change to red if the target area is not suitable to accept the card
        private void OnDropTargetDragEnter(object sender, SurfaceDragDropEventArgs e)
        {
            if (e.Cursor.Data is Task)
            {
                Task data = e.Cursor.Data as Task;

                if (data.StoryName == this.StoryName)
                {
                    data.CanDrop = true;
                }
                else
                {
                    data.CanDrop = false;
                }

                if (!data.CanDrop)
                {
                    e.Effects = DragDropEffects.None;
                }
            }
        }

        private void OnDropTargetDragLeave(object sender, SurfaceDragDropEventArgs e)
        {
            if (e.Cursor.Data is Task)
            {               
                Task data = e.Cursor.Data as Task;
                data.CanDrop = false;

                //if (data.StoryName == this.StoryName)
                //{
                //    data.CanDrop = false;
                //}
                //else
                //{
                //    data.CanDrop = false;
                //}
                // Reset the effects.
                e.Effects = e.Cursor.AllowedEffects;
            }
        }

        private void OnTargetChanged(object sender, TargetChangedEventArgs e)
        {
            if (e.Cursor.CurrentTarget != null)
            {
                Task data = e.Cursor.Data as Task;

                e.Cursor.Visual.Tag = (data.CanDrop) ? "CanDrop" : "CannotDrop";
            }
            else
            {
                e.Cursor.Visual.Tag = null;
            }
        }

        #endregion

        #region Insertion Helpers

        // controls to help swap and insert task cards inside the listbox
        public delegate Point GetDragDropPosition(IInputElement theElement);

        private bool isTheCursorOnTarget(Visual target, GetDragDropPosition pos)
        {
            Rect posBounds = VisualTreeHelper.GetDescendantBounds(target);
            Point theCursorPos = pos((IInputElement)target);
            return posBounds.Contains(theCursorPos);
        }

        private ListBoxItem GetListBoxItem(ListBox listBox, int index)
        {
            if (listBox.ItemContainerGenerator.Status != System.Windows.Controls.Primitives.GeneratorStatus.ContainersGenerated)
                return null;
            return listBox.ItemContainerGenerator.ContainerFromIndex(index) as ListBoxItem;
        }

        private int GetListBoxItemCurrentIndex(ListBox listBox, GetDragDropPosition pos)
        {
            int curIndex = -1;
            for (int i = 0; i < listBox.Items.Count; i++)
            {
                ListBoxItem item = GetListBoxItem(listBox, i);
                if (isTheCursorOnTarget(item, pos))
                {
                    curIndex = i;
                    break;
                }
            }
            return curIndex;
        }

        #endregion

    }
}
